| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- 'use client';
- import { useState, useEffect, useCallback } from 'react';
- import { fetchApi } from '@/lib/utils/client';
- import { useStudioContext } from '@/app/studio/context';
- import type { CrewWidgetConfigResponse, CrewWidgetConfigItem } from '@/types/response/crew/widgetConfig';
- import { CREW_PERIODS, CREW_WIDGET_THEMES } from '../../widget/constants';
- import { type FormState, createEmptyForm, formatDateTime } from '../../widget/types';
- import CrewWidgetFormPanel from '../../widget/_components/CrewWidgetFormPanel';
- import CrewWidgetPreviewPanel from '../../widget/_components/CrewWidgetPreviewPanel';
- import { Button } from '@/components/ui/button';
- import { Checkbox } from '@/components/ui/checkbox';
- import { Separator } from '@/components/ui/separator';
- type Props = { crewID: number };
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- export default function CrewWidgetTab({ crewID: _crewID }: Props)
- {
- const { channelID } = useStudioContext();
- const [items, setItems] = useState<CrewWidgetConfigItem[]>([]);
- const [loading, setLoading] = useState(true);
- const [saving, setSaving] = useState(false);
- const [editItem, setEditItem] = useState<CrewWidgetConfigItem|null>(null);
- const [showForm, setShowForm] = useState(false);
- const [selected, setSelected] = useState<Set<number>>(new Set());
- const [form, setForm] = useState<FormState>(createEmptyForm());
- const fetchList = useCallback(() => {
- if (!channelID) {
- setLoading(false);
- return;
- }
- setLoading(true);
- fetchApi<CrewWidgetConfigResponse>(`/api/studio/crew/widget/config/${channelID}`)
- .then(res => setItems(res.data?.list ?? []))
- .catch(() => {})
- .finally(() => setLoading(false));
- }, [channelID]);
- useEffect(() => {
- fetchList();
- }, [fetchList]);
- const getPeriodLabel = (p: number) => CREW_PERIODS.find(x => x.value === p)?.label ?? '-';
- const getThemeLabel = (t: number) => CREW_WIDGET_THEMES.find(x => x.value === t)?.label ?? '-';
- const openAdd = () => {
- setEditItem(null);
- setForm(createEmptyForm());
- setShowForm(true);
- };
- const openEdit = (item: CrewWidgetConfigItem) => {
- setEditItem(item);
- setShowForm(true);
- };
- const handleSaved = () => {
- setShowForm(false);
- setEditItem(null);
- fetchList();
- };
- const toggleSelect = (id: number) => {
- setSelected(prev => {
- const next = new Set(prev);
- if (next.has(id)) {
- next.delete(id);
- } else {
- next.add(id);
- }
- return next;
- });
- };
- const handleBatchDelete = async () => {
- if (selected.size === 0) {
- return;
- }
- if (!confirm(`${selected.size}개 설정을 삭제하시겠습니까?`)) {
- return;
- }
- for (const id of selected) {
- try {
- await fetchApi(`/api/studio/crew/widget/config/${id}/${channelID}`, { method: 'DELETE' });
- } catch {
- }
- }
- setSelected(new Set());
- fetchList();
- };
- if (loading) {
- return <p className="studio-page__empty">준비 중...</p>;
- }
- if (showForm) {
- return (
- <>
- <div className="crew-members__toolbar">
- <h2 className="crew-members__subtitle">{editItem ? '위젯 수정' : '위젯 추가'}</h2>
- <Button variant="outline" size="sm" type="button" onClick={() => setShowForm(false)}>< 뒤로가기</Button>
- </div>
- <div className="pt-3 pb-3">
- <Separator orientation="horizontal" />
- </div>
- <div className="crew-widget-layout">
- <CrewWidgetPreviewPanel form={form} />
- <Separator orientation="vertical" />
- <CrewWidgetFormPanel
- editItem={editItem ?? undefined}
- form={form}
- onFormChange={setForm}
- onSaved={handleSaved}
- onCancel={() => setShowForm(false)}
- channelID={channelID ?? undefined}
- saving={saving}
- setSaving={setSaving}
- />
- </div>
- </>
- );
- }
- return (
- <div className="crew-widget">
- <div className="crew-members__toolbar pb-3">
- <h2 className="crew-members__subtitle">위젯 설정 ({items.length}개)</h2>
- <div className="studio-page__actions">
- {selected.size > 0 && (
- <Button variant="destructive" size="sm" type="button" onClick={handleBatchDelete}>{selected.size}개 삭제</Button>
- )}
- <Button size="sm" type="button" onClick={openAdd}>+ 추가</Button>
- </div>
- </div>
- <div className="studio-page__table-wrap">
- <table className="studio-page__table">
- <thead>
- <tr>
- <th><Checkbox checked={items.length > 0 && selected.size === items.length} onCheckedChange={() => setSelected(items.length === selected.size ? new Set() : new Set(items.map(i => i.id)))} /></th>
- <th>제목</th>
- <th>기간</th>
- <th>테마</th>
- <th>최대 표시</th>
- <th>활성</th>
- <th>작업</th>
- </tr>
- </thead>
- <tbody>
- {items.length === 0 ? (
- <tr><td colSpan={7} className="studio-page__empty">등록된 위젯 설정이 없습니다.</td></tr>
- ) : items.map(item => (
- <tr key={item.id}>
- <td><Checkbox checked={selected.has(item.id)} onCheckedChange={() => toggleSelect(item.id)} /></td>
- <td>{item.title}</td>
- <td>
- {getPeriodLabel(item.period)}
- {item.period === 5 && item.startAt && item.endAt && (
- <div className="text-xs text-muted-foreground">{formatDateTime(item.startAt)} ~ {formatDateTime(item.endAt)}</div>
- )}
- </td>
- <td>{getThemeLabel(item.theme)}</td>
- <td>{item.maxDisplayCount}명</td>
- <td><span className={`studio-page__badge studio-page__badge--${item.isActive ? 'active' : 'inactive'}`}>{item.isActive ? '활성' : '비활성'}</span></td>
- <td><Button variant="outline" size="sm" type="button" onClick={() => openEdit(item)}>수정</Button></td>
- </tr>
- ))}
- </tbody>
- </table>
- </div>
- </div>
- );
- }
|